#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <fstream>
#include "../comm/log.hpp"
#include "../comm/util.hpp"

namespace ns_model
{
    using namespace ns_log;
    using namespace ns_util;

    struct Question
    {
        std::string number; // 题号
        std::string name; // 题目名称
        std::string difficulty; // 难度
        int cpu_limit; // cpu 限制
        int mem_limit; // 内存限制

        std::string desc; // 题目描述
        std::string header; // 代码初始状态
        std::string tail; // 测试内容
    };

    const std::string question_list = "./questions/question.list";
    const std::string question_comm = "./questions/";
    
    // 加载题目信息
    class Model
    {
    private:
    // 题号 -- 题目详情
        std::unordered_map<std::string, Question> _IndexToQuestion;
    public:
        Model()
        {
            assert(LoadQuestionList(question_list));
        };
        ~Model() = default;

        bool LoadQuestionList(const std::string& list_name)
        {
            std::ifstream ifs(list_name);
            if(!ifs.is_open())
            {
                LOG(FATAL) << "文件列表打开失败，请检查文件列表是否存在！" << std::endl;
                return false;
            }

            // 读取文件列表信息
            std::string line;
            while(std::getline(ifs, line))
            {
                std::vector<std::string> v;
                // 切割字符串
                StringUtil::SpiltString(line, &v, " ");
                if(v.size() != 5)
                {
                    LOG(WARNING) << "题目列表格式错误" << std::endl;
                    continue;
                }
                // 填信息
                Question q;
                q.number = v[0];
                q.name = v[1];
                q.difficulty = v[2];
                q.cpu_limit = std::stoi(v[3]);
                q.mem_limit = std::stoi(v[4]);

                // 读取文件填写描述，头和测试
                // question_comm + v[0] + "/desc.txt" -- ./questions/1/desc.txt
                if(!FileUtil::ReadFile(question_comm + v[0] + "/desc.txt", &q.desc, true))
                {
                    LOG(WARNING) << "题目描述获取失败" << std::endl;
                }
                // ./questions/1/header.cpp
                if(!FileUtil::ReadFile(question_comm + v[0] + "/header.cpp", &q.header, true))
                {
                    LOG(WARNING) << "题目初始代码获取失败" << std::endl;
                }
                // ./questions/1/tail.cpp
                if(!FileUtil::ReadFile(question_comm + v[0] + "/tail.cpp", &q.tail, true))
                {
                    LOG(WARNING) << "题目测试文件获取失败" << std::endl;
                }

                _IndexToQuestion.insert({q.number, q});
            }

            LOG(INFO) << "题库加载成功!" << std::endl;
            return true;
        }

        bool GetAllQuestions(std::vector<Question>* ret)
        {
            if(_IndexToQuestion.size() == 0)
            {
                LOG(ERROR) << "全部问题获取失败" << std::endl;
                return false;
            }
            
            for(const auto& e : _IndexToQuestion)
            {
                ret->push_back(e.second);
            }
            return true;
        }

        bool GetOneQuestion(const std::string num, Question* q)
        {
            auto iter = _IndexToQuestion.find(num);
            if(iter == _IndexToQuestion.end())
            {
                LOG(ERROR) << "获取单个问题失败，编号为" << num << std::endl;
                return false;
            }
            (*q) = iter->second;
            return true;
        }
    };
}
